2 * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
23 Change History (most recent first):
25 $Log: Mac\040OS\040Test\040Searcher.c,v $
26 Revision 1.13 2003/08/14 02:19:54 cheshire
27 <rdar://problem/3375491> Split generic ResourceRecord type into two separate types: AuthRecord and CacheRecord
29 Revision 1.12 2003/08/12 19:56:24 cheshire
34 #include <stdio.h> // For printf()
35 #include <Events.h> // For WaitNextEvent()
36 #include <SIOUX.h> // For SIOUXHandleOneEvent()
38 #include "mDNSClientAPI.h" // Defines the interface to the client layer above
39 #include "mDNSMacOS9.h" // Defines the specific types needed to run mDNS on this platform
43 OTLIFO serviceinfolist
;
44 Boolean headerPrinted
;
48 typedef struct { ServiceInfo i
; mDNSBool add
; mDNSBool dom
; OTLink link
; } linkedServiceInfo
;
50 // These don't have to be globals, but their memory does need to remain valid for as
51 // long as the search is going on. They are declared as globals here for simplicity.
52 #define RR_CACHE_SIZE 1000
53 static CacheRecord rrcachestorage
[RR_CACHE_SIZE
];
54 static mDNS mDNSStorage
;
55 static mDNS_PlatformSupport PlatformSupportStorage
;
56 static SearcherServices services
;
57 static DNSQuestion browsequestion
, domainquestion
;
59 // PrintServiceInfo prints the service information to standard out
60 // A real application might want to do something else with the information
61 static void PrintServiceInfo(SearcherServices
*services
)
63 OTLink
*link
= OTReverseList(OTLIFOStealList(&services
->serviceinfolist
));
67 linkedServiceInfo
*ls
= OTGetLinkObject(link
, linkedServiceInfo
, link
);
68 ServiceInfo
*s
= &ls
->i
;
70 if (!services
->headerPrinted
)
72 printf("%-55s Type Domain IP Address Port Info\n", "Name");
73 services
->headerPrinted
= true;
79 ConvertDomainNameToCString(&s
->name
, c_dom
);
80 if (ls
->add
) printf("%-55s available for browsing\n", c_dom
);
81 else printf("%-55s no longer available for browsing\n", c_dom
);
86 domainname type
, domain
;
87 UInt16 port
= (UInt16
)((UInt16
)s
->port
.b
[0] << 8 | s
->port
.b
[1]);
88 char c_name
[64], c_type
[256], c_dom
[256], c_ip
[20];
90 DeconstructServiceName(&s
->name
, &name
, &type
, &domain
);
91 ConvertDomainLabelToCString_unescaped(&name
, c_name
);
92 ConvertDomainNameToCString(&type
, c_type
);
93 ConvertDomainNameToCString(&domain
, c_dom
);
94 sprintf(c_ip
, "%d.%d.%d.%d", s
->ip
.ip
.v4
.b
[0], s
->ip
.ip
.v4
.b
[1], s
->ip
.ip
.v4
.b
[2], s
->ip
.ip
.v4
.b
[3]);
96 printf("%-55s %-16s %-14s ", c_name
, c_type
, c_dom
);
97 if (ls
->add
) printf("%-15s %5d %#s\n", c_ip
, port
, s
->TXTinfo
);
98 else printf("Removed\n");
106 // When the name, address, port, and txtinfo for a service is found, FoundInstanceInfo()
107 // enqueues a record for PrintServiceInfo() to print.
108 // Note, a browsing application would *not* normally need to get all this information --
109 // all it needs is the name, to display to the user.
110 // Finding out the address, port, and txtinfo should be deferred to the time that the user
111 // actually needs to contact the service to use it.
112 static void FoundInstanceInfo(mDNS
*const m
, ServiceInfoQuery
*query
)
114 SearcherServices
*services
= (SearcherServices
*)query
->ServiceInfoQueryContext
;
115 linkedServiceInfo
*info
= (linkedServiceInfo
*)(query
->info
);
116 if (query
->info
->ip
.type
== mDNSAddrType_IPv4
)
118 mDNS_StopResolveService(m
, query
); // For this test code, one answer is sufficient
119 OTLIFOEnqueue(&services
->serviceinfolist
, &info
->link
);
124 // When a new named instance of a service is found, FoundInstance() is called.
125 // In this sample code we turn around and immediately issue a query to resolve that service name to
126 // find its address, port, and txtinfo, but a normal browing application would just display the name.
127 static void FoundInstance(mDNS
*const m
, DNSQuestion
*question
, const ResourceRecord
*const answer
, mDNSBool AddRecord
)
129 #pragma unused (question)
130 SearcherServices
*services
= (SearcherServices
*)question
->QuestionContext
;
131 linkedServiceInfo
*info
;
133 debugf("FoundInstance %##s PTR %##s", answer
->name
.c
, answer
->rdata
->u
.name
.c
);
135 if (answer
->rrtype
!= kDNSType_PTR
) return;
136 if (!services
) { debugf("FoundInstance: services is NULL"); return; }
138 info
= (linkedServiceInfo
*)OTAllocMem(sizeof(linkedServiceInfo
));
139 if (!info
) { services
->lostRecords
= true; return; }
141 info
->i
.name
= answer
->rdata
->u
.name
;
142 info
->i
.InterfaceID
= answer
->InterfaceID
;
143 info
->i
.ip
.type
= mDNSAddrType_IPv4
;
144 info
->i
.ip
.ip
.v4
= zeroIPAddr
;
145 info
->i
.port
= zeroIPPort
;
146 info
->add
= AddRecord
;
147 info
->dom
= mDNSfalse
;
149 if (!AddRecord
) // If TTL == 0 we're deleting a service,
150 OTLIFOEnqueue(&services
->serviceinfolist
, &info
->link
);
151 else // else we're adding a new service
153 ServiceInfoQuery
*q
= (ServiceInfoQuery
*)OTAllocMem(sizeof(ServiceInfoQuery
));
154 if (!q
) { OTFreeMem(info
); services
->lostRecords
= true; return; }
155 mDNS_StartResolveService(m
, q
, &info
->i
, FoundInstanceInfo
, services
);
159 static void FoundDomain(mDNS
*const m
, DNSQuestion
*question
, const ResourceRecord
*const answer
, mDNSBool AddRecord
)
162 #pragma unused (question)
163 SearcherServices
*services
= (SearcherServices
*)question
->QuestionContext
;
164 linkedServiceInfo
*info
;
166 debugf("FoundDomain %##s PTR %##s", answer
->name
.c
, answer
->rdata
->u
.name
.c
);
168 if (answer
->rrtype
!= kDNSType_PTR
) return;
169 if (!services
) { debugf("FoundDomain: services is NULL"); return; }
171 info
= (linkedServiceInfo
*)OTAllocMem(sizeof(linkedServiceInfo
));
172 if (!info
) { services
->lostRecords
= true; return; }
174 info
->i
.name
= answer
->rdata
->u
.name
;
175 info
->i
.InterfaceID
= answer
->InterfaceID
;
176 info
->i
.ip
.type
= mDNSAddrType_IPv4
;
177 info
->i
.ip
.ip
.v4
= zeroIPAddr
;
178 info
->i
.port
= zeroIPPort
;
179 info
->add
= AddRecord
;
180 info
->dom
= mDNStrue
;
182 OTLIFOEnqueue(&services
->serviceinfolist
, &info
->link
);
185 // YieldSomeTime() just cooperatively yields some time to other processes running on classic Mac OS
186 static Boolean
YieldSomeTime(UInt32 milliseconds
)
188 extern Boolean SIOUXQuitting
;
190 WaitNextEvent(everyEvent
, &e
, milliseconds
/ 17, NULL
);
191 SIOUXHandleOneEvent(&e
);
192 return(SIOUXQuitting
);
197 extern void mDNSPlatformIdle(mDNS
*const m
); // Only needed for debugging version
199 Boolean DoneSetup
= false;
201 SIOUXSettings
.asktosaveonclose
= false;
202 SIOUXSettings
.userwindowtitle
= "\pMulticast DNS Searcher";
203 SIOUXSettings
.rows
= 40;
204 SIOUXSettings
.columns
= 132;
206 printf("Prototype Multicast DNS Searcher\n\n");
207 printf("WARNING! This is experimental software.\n\n");
208 printf("Multicast DNS is currently an experimental protocol.\n\n");
209 printf("This software reports errors using MacsBug breaks,\n");
210 printf("so if you don't have MacsBug installed your Mac may crash.\n\n");
211 printf("******************************************************************************\n");
213 err
= InitOpenTransport();
214 if (err
) { debugf("InitOpenTransport failed %d", err
); return(err
); }
216 err
= mDNS_Init(&mDNSStorage
, &PlatformSupportStorage
, rrcachestorage
, RR_CACHE_SIZE
,
217 mDNS_Init_DontAdvertiseLocalAddresses
, mDNS_Init_NoInitCallback
, mDNS_Init_NoInitCallbackContext
);
218 if (err
) return(err
);
220 services
.serviceinfolist
.fHead
= NULL
;
221 services
.headerPrinted
= false;
222 services
.lostRecords
= false;
224 while (!YieldSomeTime(35))
226 // For debugging, use "#define __ONLYSYSTEMTASK__ 1" and call mDNSPlatformIdle() periodically.
227 // For shipping code, don't define __ONLYSYSTEMTASK__, and you don't need to call mDNSPlatformIdle()
228 mDNSPlatformIdle(&mDNSStorage
); // Only needed for debugging version
229 if (mDNSStorage
.mDNSPlatformStatus
== mStatus_NoError
&& !DoneSetup
)
231 domainname srvtype
, srvdom
;
233 printf("\nSending mDNS service lookup queries and waiting for responses...\n\n");
234 MakeDomainNameFromDNSNameString(&srvtype
, "_http._tcp.");
235 MakeDomainNameFromDNSNameString(&srvdom
, "local.");
236 err
= mDNS_StartBrowse(&mDNSStorage
, &browsequestion
, &srvtype
, &srvdom
, mDNSInterface_Any
, FoundInstance
, &services
);
238 err
= mDNS_GetDomains(&mDNSStorage
, &domainquestion
, mDNS_DomainTypeBrowse
, mDNSInterface_Any
, FoundDomain
, &services
);
242 if (services
.serviceinfolist
.fHead
)
243 PrintServiceInfo(&services
);
245 if (services
.lostRecords
)
247 services
.lostRecords
= false;
248 printf("**** Warning: Out of memory: Records have been missed.\n");
252 mDNS_StopBrowse(&mDNSStorage
, &browsequestion
);
253 mDNS_Close(&mDNSStorage
);